﻿using System;
using System.Collections.Generic;
using System.Drawing;
using System.Drawing.Imaging;
using System.Globalization;
using System.IO;
using System.Text;
using System.Xml.Serialization;
using SAS.Core;
using SAS.Core.Entity;
using SAS.Core.Result;
using SAS.DataAccess;

namespace SAS.Bussiness
{
    public abstract class BaseBO
    {
        public string FromIP { get; set; }

        protected string CreateCondition(SearchParameters advsrch, Dictionary<string, object> paramvals)
        {
            //Create SQL search conditions
            string searchCondition = CreateSearchString(advsrch);

            //Create SQL column filter condition
            string filterCondition = CreateFilterString(paramvals);

            //Build SQL condition
            string condition = String.IsNullOrEmpty(searchCondition) && String.IsNullOrEmpty(filterCondition)
                                   ? String.Empty
                                   : String.Format("{0} {1}", searchCondition, String.IsNullOrEmpty(filterCondition) 
                                                                                     ? String.Empty
                                                                                     : String.Format("AND ({0})", filterCondition));

            return condition;
        }

        private string CreateSearchString(SearchParameters advsrch)
        {
            StringBuilder sbadvsearch = new StringBuilder();
            if (advsrch != null)
            {
                sbadvsearch.Append(" AND (");
                sbadvsearch.Append(ExtractAdvSearch(advsrch));
                if (sbadvsearch.Length > 7)
                {
                    sbadvsearch.Append(")");
                }
                else
                {
                    sbadvsearch.Clear();
                }
            }

            return sbadvsearch.ToString();

        }

        public static string CreateFilterString(Dictionary<string, object> paramvals)
        {   
            int rowcnt = 0;
            string andor = " AND ";
            StringBuilder sbadvsearch = new StringBuilder();
            StringBuilder sbfilter = new StringBuilder();
          
            if ((paramvals != null) && (paramvals.Count > 0))
            {
                
                foreach (KeyValuePair<string, object> item in paramvals)
                {
                    if (rowcnt > 0)
                    {
                        sbfilter.Append(andor);
                    }
                    switch (item.Key)
                    {
                        case "AddPrintYN":
                            sbfilter.Append(String.Format("cast(case AddPrint when 1 then 'Y' else 'N' end as varchar(10)) LIKE '%{0}%'", item.Value.ToString().ToLower().Trim()));
                            break;
                        case "BatchName":
                        case "BatchNumLink":
                            sbfilter.Append(String.Format("BatchInName + '-' + CONVERT(varchar(10),pkBatchIn_ID) LIKE '%{0}%'", item.Value.ToString().ToLower().Trim()));
                            break;
                        case "MessageLink":
                        case "MessageNum":
                            sbfilter.Append(String.Format("CONVERT(varchar(10),pkMessage_ID) + '-' + CONVERT(varchar(3),MessageVersionNum) LIKE '%{0}%'", item.Value.ToString().ToLower().Trim()));
                            break;
                        case "MessageNumPrefLink":
                        case "MessageNumPref":
                            sbfilter.Append(String.Format("CONVERT(varchar(10),pkMessage_ID) + '-#' LIKE '%{0}%'", item.Value.ToString().ToLower().Trim()));
                            break;
                        default:
                            sbfilter.Append(String.Format(item.Key.Replace("Link", "") + " LIKE '%{0}%'", item.Value.ToString().ToLower().Trim()));
                            break;
                    }
                    rowcnt++;
                }
                if (sbfilter.Length > 7)
                {
                    
                }
                else
                {
                    sbfilter.Clear();
                }
            }
            return sbadvsearch + sbfilter.ToString();
        }

        private string ExtractAdvSearch(SearchParameters advsrch)
        {
            StringBuilder sbadvsearch = new StringBuilder();

            string tolower = string.Empty;
            string stringticks = string.Empty;
            int rowcnt = 0;
            string andor = " AND ";
            

            foreach (SearchParameter sp in advsrch.Items)
            {
                if (rowcnt > 0)
                {
                    switch (advsrch.Andor)
                    {
                        case "&&":
                            andor = " AND ";
                            break;
                        case "AND":
                            andor = " AND ";
                            break;
                        case "||":
                            andor = " OR ";
                            break;
                        case "OR":
                            andor = " OR ";
                            break;
                    }
                    sbadvsearch.Append(andor);
                }
                if ((sp.Datatype.Contains("str")) || (sp.Datatype.Contains("cbo")) || (sp.Datatype.Contains("yn")) || (sp.Datatype.Contains("date")))
                {
                    tolower = "";
                    stringticks = "'";
                }
                else
                {
                    tolower = "";
                    stringticks = "";
                }
                int opIndex = Convert.ToInt32(sp.Operator);
                string oprtr = string.Empty;
                string notstring = string.Empty;
                bool isStringNotNullOperator = false;
                switch (opIndex)
                {
                    case 0:
                        oprtr = "={0}";
                        break;
                    case 1:
                        oprtr = "<>{0}";
                        break;
                    case 2:
                        oprtr = "<{0}";
                        break;
                    case 3:
                        oprtr = "<={0}";
                        break;
                    case 4:
                        oprtr = ">{0}";
                        break;
                    case 5:
                        oprtr = ">={0}";
                        break;
                    case 6:
                        oprtr = "=null";
                        break;
                    case 7:
                        notstring = " NOT ";
                        oprtr = "=null";
                        break;
                    case 8:
                        oprtr = "?=''";
                        break;
                    case 9:
                        isStringNotNullOperator = true;
                        notstring = " NOT ";
                        oprtr = "=''";
                        break;
                    case 10:
                        oprtr = " like '{0}%'";
                        stringticks = "";
                        break;
                    case 11:
                        notstring = " NOT ";
                        oprtr = " like '{0}%'";
                        stringticks = "";
                        break;
                    case 12:
                        oprtr = " like '%{0}'";
                        stringticks = "";
                        break;
                    case 13:
                        notstring = " NOT ";
                        oprtr = " like '%{0}'";
                        stringticks = "";
                        break;
                    case 14:
                        oprtr = " like '%{0}%'";
                        stringticks = "";
                        break;
                    case 15:
                        notstring = " NOT ";
                        oprtr = " like '%{0}%'";
                        stringticks = "";
                        break;
                    case 16:
                        oprtr = "?{1}{1}";
                        break;
                    case 17:
                        notstring = " NOT ";
                        oprtr = "?{1}{1}";
                        break;
                    case 18:
                        oprtr = "<{1}";
                        break;
                    case 19:
                        oprtr = "<={1}";
                        break;
                    case 20:
                        oprtr = ">{1}";
                        break;
                    case 21:
                        oprtr = ">={1}";
                        break;
                    case 22:
                        oprtr = "?{1}{2}";
                        break;
                    case 23:
                        oprtr = "={3}";
                        break;
                    case 24:
                        oprtr = "<>{3}";
                        break;
                    case 25:
                        oprtr = " <= '01/01/1900'";
                        break;
                    case 26:
                        oprtr = " > '01/01/1900'";
                        break;

                }
                sp.Column = sp.Column.Replace("dt", "");
                string column;
                bool isOrinalColumn = false;
                switch (sp.Column)
                {
                    case "AddPrint":
                        column = sp.Column;
                        if (sp.Value3 == "Y")
                        {
                            sp.Value3 = "1";
                        }
                        else if (sp.Value3 == "N")
                        {
                            sp.Value3 = "0";
                        }
                        break;
                    case "BatchName":
                    case "BatchNumLink":
                        column = "BatchInName + '-' + CONVERT(varchar(10),pkBatchIn_ID)";
                        break;
                    case "MessageLink":
                    case "MessageNum":
                        column = "CONVERT(varchar(10),pkMessage_ID) + '-' + CONVERT(varchar(3),MessageVersionNum)";
                        break;
                    case "MessageNumPref":
                        column = "CONVERT(varchar(10),pkMessage_ID) + '-#'";
                        break;
                    default:
                        isOrinalColumn = true;
                        column = sp.Column;
                        break;
                }


                if ((oprtr.StartsWith("?")) && (sp.Datatype.Contains("date")))
                {
                    if (sp.Value2.Length <= 0)
                    {
                        sp.Value2 = sp.Value1;
                    }
                    sbadvsearch.Append(String.Format(notstring + "(" + column + " BETWEEN '{0} 00:00:00' AND '{1} 23:59:59' OR " + column + " BETWEEN '{1} 00:00:00' AND '{0} 23:59:59')", sp.Value1, sp.Value2));
                }
                else if ((oprtr.StartsWith("?")) && (sp.Datatype.Contains("str")))
                {
                    sbadvsearch.Append(notstring);
                    sbadvsearch.Append("(");
                    sbadvsearch.Append(column);
                    sbadvsearch.Append(" IS NULL OR ");
                    sbadvsearch.Append(column);
                    sbadvsearch.Append(" = '')");
                }
                else
                {   
                    // it's apply only for String and column name is not changed, operator is not "is not null"
                    if (isOrinalColumn && (sp.Datatype.Contains("str") && !isStringNotNullOperator))
                        column = string.Format(" ISNULL ( {0}, '') ", column);

                    sbadvsearch.Append(String.Format(notstring + column + oprtr, stringticks + sp.Value0.ToString(CultureInfo.InvariantCulture).ToLower().Trim() + stringticks, stringticks + sp.Value1.ToString(CultureInfo.InvariantCulture).ToLower().Trim() + stringticks, stringticks + sp.Value2.ToString(CultureInfo.InvariantCulture).ToLower().Trim() + stringticks, stringticks + sp.Value3.ToString(CultureInfo.InvariantCulture).ToLower().Trim() + stringticks));
                }
                rowcnt++;
            }
            return sbadvsearch.ToString();
        }

        /// <summary>
        /// Get object from xml data.
        /// </summary>
        /// <typeparam name="T">Type of object</typeparam>
        /// <param name="xmlString">Xml data string</param>
        /// <returns>object returned</returns>
        protected T DeSerialize<T>(string xmlString) where T : class
        {

            ////Create stream from xml data.
            //MemoryStream memoryStream = new MemoryStream();
            //StreamWriter streamWriter = new StreamWriter(memoryStream);
            //streamWriter.Write(xmlString);
            TextReader reader = new StringReader(xmlString);
            //Deserialize to object from stream.  
            XmlSerializer serializer = new XmlSerializer(typeof(T));
            return serializer.Deserialize(reader) as T;
        }

        /// <summary>
        /// Serialize and object to xml data
        /// </summary>
        /// <typeparam name="T">Type of object</typeparam>
        /// <param name="objectToSerialize">object will be serialized</param>
        /// <returns>Xml string</returns>
        protected string Serialize<T>(T objectToSerialize) where T : class
        {
            XmlSerializer serializer = new XmlSerializer(typeof(T));
            MemoryStream memoryStream = new MemoryStream();
            serializer.Serialize(memoryStream, objectToSerialize);
            StreamReader clientStreamReader = new StreamReader(memoryStream);
            memoryStream.Position = 0;
            return clientStreamReader.ReadToEnd();
        }

        /// <summary>
        /// Convert stream to base64 string
        /// </summary>
        /// <param name="inputStream">Stream</param>
        /// <param name="size">size of stream</param>
        /// <param name="logoName">size of stream</param>
        /// <returns></returns>
        protected string ImageStreamToBase64(Stream inputStream, string logoName, int size)
        {
            if (inputStream == null) return String.Empty;

            ImageFormat imageFormat = ImageFormat.Png;

            string extention = Path.GetExtension(logoName).ToLower().Replace(".", String.Empty);

            switch (extention)
            {
                case "png":
                    imageFormat = ImageFormat.Png;
                    break;
                case "jpg":
                    imageFormat = ImageFormat.Jpeg;
                    break;
                case "bmp":
                    imageFormat = ImageFormat.Bmp;
                    break;
                case "tif":
                    imageFormat = ImageFormat.Tiff;
                    break;

            }

            if (inputStream.Length == 0) return String.Empty;

            var image = Image.FromStream(inputStream);
            MemoryStream ms = new MemoryStream();
            image.Save(ms, imageFormat);
            string b64 = Convert.ToBase64String(ms.ToArray());
            string base64ImageString = String.Format("data:image/{0};base64,{1}", extention, b64);
            return base64ImageString;
        }

        protected bool ValidateCurrentUser<T>(User currentUser, SASResult<T> bussinessResult)
        {
            UserDAO userDAO = new UserDAO(currentUser.TokenKey);

            SASResult<string> validateResult = userDAO.ValidateToken(FromIP);

            if (!validateResult.IsSucessful)
            {
                bussinessResult.Message = "Can not validate current user";
                return false;
            }
            //if (!validateResult.Result)
            //{
            //    bussinessResult.Message = "User is not logged in system";
            //    return false;
            //}
            return true;
        }

        protected void Log(Exception exception)
        {
            
        }
    }
}